package br.gov.cemaden.cliente.inmet;


import br.gov.cemaden.cliente.inmet.exception.NoDataException;
import br.gov.cemaden.library.model.Municipio;
import br.gov.cemaden.library.model.alerta.Direcao;
import br.gov.cemaden.library.model.previsao.PrevisaoTempo;
import br.gov.cemaden.library.util.Util;
import java.io.BufferedReader;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author alan
 */
public class JSONReader {
    
    DateFormat dateFormat;
    Logger logger;    

    public JSONReader() {
        dateFormat = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
        logger = LoggerFactory.getLogger(JSONReader.class);        
    }
    
    public List<PrevisaoTempo> getPrevisoes(BufferedReader reader, Municipio municipio) 
            throws IOException, ParseException, NoDataException, java.text.ParseException {        
        
        List<PrevisaoTempo> previsoes = new ArrayList<PrevisaoTempo>();
        
        Map<String, String> periodos = new HashMap<String, String>();
        periodos.put("manha", "00:00:00");
        periodos.put("tarde", "12:00:00");
        periodos.put("noite", "18:00:00");
        
        Map<Long, JSONObject> dados = parse(reader, municipio, periodos);
        
        List<Long> indices = new ArrayList<Long>(dados.keySet());

        for (Map.Entry<Long, JSONObject> dado : dados.entrySet()) {                        

            PrevisaoTempo previsao = new PrevisaoTempo();            
            previsao.setDatahora(Util.parseDateFromLocalToGMT(new Date(dado.getKey())));

            Calendar c = Calendar.getInstance();
            c.setTime(previsao.getDatahora());
            Integer hora = c.get(Calendar.HOUR_OF_DAY);

            previsao.setPeriodo(24);

            /* Horal local = 0; GMT = 3 */
            if (hora == 3) {
                Integer nextIndex = indices.indexOf(dado.getKey()) + 1;
                if (indices.size() > nextIndex) {
                    if (indices.get(nextIndex) < (dado.getKey() + (24 * 60 * 60 * 1000L))) {
                        previsao.setPeriodo(12);
                    }
                }
            } else {
                previsao.setPeriodo(6);
            }

            previsao.setMunicipio(municipio);
            previsao.setMaxima(Double.parseDouble(dado.getValue().get("temp_max").toString()));
            previsao.setMinima(Double.parseDouble(dado.getValue().get("temp_min").toString())); 
            if(dado.getValue().containsKey("resumo")){
                try{
                    previsao.setCondicao(dado.getValue().get("resumo").toString());
                }
                catch(NullPointerException ex){
                    logger.error("O campo \"resumo\" encontra-se vazio para a localidade " + municipio.getCidade() + " - " + municipio.getCodIBGE(), ex);
                }
            }
            
            String direcao = dado.getValue().get("dir_vento").toString();
            Integer indice = (direcao.indexOf("-") > 0) ? direcao.indexOf("-") : direcao.length();
            previsao.setDirecaoVento(Direcao.valueOf(direcao.substring(0, indice).trim().toUpperCase()).getAngulo());
            previsao.setIntensidadeVento(dado.getValue().get("int_vento").toString());
            previsao.setVelocidadeVento(null);

            previsoes.add(previsao);
        }
        
        return previsoes;
    }

    private Map<Long, JSONObject> parse(BufferedReader reader, Municipio municipio, Map<String, String> periodos) 
            throws IOException, ParseException, NoDataException {
        
        JSONParser parser = new JSONParser();
        
        JSONObject json = (JSONObject) parser.parse(reader);

        JSONObject localidade = (JSONObject) json.get(municipio.getCodIBGE().toString());

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE, -1);
        String futuro = new SimpleDateFormat("dd-MM-yyyy").format(calendar.getTime());

        if (localidade.containsKey(futuro)) {
            throw new NoDataException("There aren't new data for this municipio");
        }

        TreeMap<Long, JSONObject> dados = new TreeMap<Long, JSONObject>();

        for (Iterator i = localidade.entrySet().iterator(); i.hasNext();) {

            Object bigbox = i.next();

            if (bigbox instanceof Map.Entry) {

                Map.Entry bigdata = (Map.Entry) bigbox;

                if (bigdata.getValue() instanceof JSONObject) {

                    JSONObject dado = (JSONObject) bigdata.getValue();

                    Long datetime = null;

                    try {
                        datetime = dateFormat.parse(String.format("%s %s", bigdata.getKey().toString(), "00:00:00")).getTime();
                    } catch (java.text.ParseException ex) {
                        logger.error("Error when parsing date", ex);
                        continue;
                    }

                    dados.put(datetime, dado);

                    // Iteração sobre o conteudo de JSONObject para verificar se ele possui outros JSONObjects
                    for (Iterator n = dado.entrySet().iterator(); n.hasNext();) {

                        Object box = n.next();

                        if (box instanceof Map.Entry) {

                            Map.Entry data = (Map.Entry) box;

                            if (data.getValue() instanceof JSONObject) {

                                JSONObject dadoHorario = (JSONObject) data.getValue();

                                try {
                                    datetime = dateFormat.parse(String.format("%s %s", bigdata.getKey().toString(), periodos.get(data.getKey().toString()))).getTime();
                                } catch (java.text.ParseException ex) {
                                    logger.error("Error when parsing date", ex);
                                    continue;
                                }
                                dados.put(datetime, dadoHorario);
                            }
                        }
                    }
                }
            }
        }
        
        return dados;
    }

}
